package controller;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.swing.JFrame;
import service.ChatClientService;
import service.ChatServerService;
import view.ChatWindow;
import view.Login;
import dto.Account;
import dto.Message;

import java.awt.Frame;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.util.ArrayList;
import java.util.Collection;

import javax.swing.ImageIcon;

import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Vector;
import javax.swing.AbstractListModel;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.ListModel;
import service.ChatRoomInt;
import service.SessionInt;
import view.MainFrame;

public class ClientController {

    private static ChatServerService serv;
    private JFrame activeWindow;
    private ChatClientServiceImpl clientServiceImpl;
    private SessionInt accountSession;
    private HashMap<ChatRoomInt, ChatWindow> chatRooms = new HashMap<>();
    private Frame[] allFrames;
    private MainFrame mainFrameRef = null;
    private static String serverIP;

    public static void main(String[] args) {
        try {
            new ClientController();
        } catch (RemoteException | NotBoundException e) {
            e.printStackTrace();
        }
    }

    public ClientController() throws RemoteException, NotBoundException {
        
        clientServiceImpl = new ChatClientServiceImpl();
        clientServiceImpl.setClient(this);

        activeWindow = new Login();
        activeWindow.setTitle("Login_Form");
        ((Login) activeWindow).setClientController(this);
        activeWindow.setVisible(true);
    }

    public void closeAll() {
        Collection chatWindows = getChatRooms().values();
        Iterator itr = chatWindows.iterator();
        while (itr.hasNext()) {
            ChatWindow window = (ChatWindow) itr.next();
            window.terminateYourself();
        }
        getChatRooms().clear();
        lunchLogin();
        activeWindow.dispose();
    }

    public void reciveMessage(Message message, ChatRoomInt cs) {
        ChatWindow window = getChatRooms().get(cs);
        if (window != null) {
            window.appendMessage(message);
        } else {
            ChatWindow cw = new ChatWindow(cs);
            chatRooms.put(cs, cw);
            cw.setClientController(this);
            cw.setVisible(true);
            cw.appendMessage(message);
        }
    }
    
    public void reciveBuzz(ChatRoomInt cs) throws AssertionError{
        assert (getChatRooms().size()>0);
        ChatWindow window = getChatRooms().get(cs);
        if (window != null) {
            window.makeBuzz();
        }else {
            ChatWindow cw = new ChatWindow(cs);
            chatRooms.put(cs, cw);
            cw.setClientController(this);
            cw.setVisible(true);
            cw.makeBuzz();
        }

    }

    public void reciveFileInfo(Message message, ChatRoomInt cs) {
        ChatWindow window = chatRooms.get(cs);
        if (window != null) {
            window.appendFileMessage(message);
        } else {
            ChatWindow cw = new ChatWindow(cs);
            chatRooms.put(cs, cw);
            cw.setClientController(this);
            cw.setVisible(true);
            cw.appendFileMessage(message);
        }
    }

    public void setActiveWindow(JFrame activeWindow) {
        this.activeWindow = activeWindow;
    }
    
    /**
     * getService: return the ServerService
     */
    public static ChatServerService getService() {
        if (serv == null) {
            try {
                Registry reg = LocateRegistry.getRegistry(serverIP == null ? "127.0.0.1" : serverIP);
                serv = (ChatServerService) reg.lookup("ChatService");
            } catch (RemoteException | NotBoundException ex) {
                JOptionPane.showMessageDialog(null, "Could not connect to server", "Chat", JOptionPane.ERROR_MESSAGE);
                serv = null;
            }
        }
        return serv;
    }

    /**
     * getLoggedInAccount: return the Account.
     */
    public Account getLoggedInAccount() {
        return clientServiceImpl.getLoggedInAccount();
    }

    public void setAccount(Account a) {
        try {
            clientServiceImpl.setAccount(a);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }

    public ChatClientService getClientService() {
        return clientServiceImpl;
    }

    void notifyState(Account account) {
        ((MainFrame) activeWindow).notifyStatusChanged(account);
    }

    public ChatWindow newChatRoom(Account... accounts) throws RemoteException {
        ChatRoomInt roomRef = getAccountSession().makeNewRoom();
        roomRef.addMemberToRoom(getLoggedInAccount());
        for (Account account : accounts) {
            roomRef.addMemberToRoom(account);
        }

        if (roomRef != null) {
            getAccountSession().addChatRoom(roomRef);
        }
        System.out.println("Inside MainFrame No of rooms inside session=:" + getAccountSession().getChatRooms().size());
//        System.out.println("Inside MainFrame No. of members inside chat room=:" + roomRef.getChatRoomMembers().size());
        ChatWindow window = new ChatWindow(roomRef);
        window.setVisible(true);
        window.setClientController(this);
        getChatRooms().put(roomRef, window);
        System.out.println("Inside new chat room fn, No. of entries inside hashmap="+getChatRooms().size());
        return window;
    }

    public void lunchLogin() {
        try {
            new ClientController();
            serv = null;
        } catch (RemoteException | NotBoundException e) {
            e.printStackTrace();
        }
    }

    /** 
     * getActiveWindow: return the active window for now. 
     */
    public JFrame getActiveWindow() {
        return activeWindow;
    }
    
    /**
     * friendRequest: method to tell user that he/she got a friend request.
     */
    public void friendRequest(Account senderAccount) {
        int reply = 0;
        String friendRequest = "Hey! .. There's a new Friend Request for you ! \n" + senderAccount.getEmail() + " wants to add you to his/her contacts list. \n";
        ImageIcon friendRequestIcon = new ImageIcon("/resources/friendRequest.jpg");
        reply = JOptionPane.showConfirmDialog(activeWindow, friendRequest, "1 Friend Request for you", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, friendRequestIcon);


        ReplyThread replyThread = new ReplyThread(serv, senderAccount, clientServiceImpl.getLoggedInAccount(), reply, mainFrameRef);
        replyThread.start();


    }
    
    /**
     * friendRequestreply: method to tell user that he/she got a friend request reply.
     */
    public void friendRequestReply(Account userWhoReply, int reply) {

        String msg;
        if (reply == 0) {
            msg = "Now, You have another Friend " + userWhoReply.getEmail() + " had accepted your friend Request.";
            if (mainFrameRef != null) {
                mainFrameRef.renderContactList();
            }
        } else {
            msg = "Sorry, but " + userWhoReply.getEmail() + " refused your Friend Request.";
        }

        JOptionPane.showMessageDialog(activeWindow, msg, "Friend Request Confirmation", JOptionPane.INFORMATION_MESSAGE);
    }

    public SessionInt getAccountSession() {
        return accountSession;
    }

    /**
     * @param accountSession the accountSession to set
     */
    public void setAccountSession(SessionInt accountSession) {
        this.accountSession = accountSession;
    }

    /**
     * @return the chatRooms
     */
    public HashMap<ChatRoomInt, ChatWindow> getChatRooms() {
        return chatRooms;
    }

    /**
     * @param chatRooms the chatRooms to set
     */
    public void setChatRooms(HashMap<ChatRoomInt, ChatWindow> chatRooms) {
        this.chatRooms = chatRooms;
    }

    /**
     * @return the allFrames
     */
    public Frame[] getAllFrames() {
        return allFrames;
    }

    /**
     * @param allFrames the allFrames to set
     */
    public void setAllFrames(Frame[] allFrames) {
        this.allFrames = allFrames;
    }

    /**
     * @return the frameTitle
     */
    /**
     * @param frameTitle the frameTitle to set
     */
    /**
     * @return the loginForm
     */
    public void setMainFrameRef(MainFrame ref) {
        mainFrameRef = ref;
    }

    public void setAnnouncement(String Announcement) {
        if (mainFrameRef != null) {
            mainFrameRef.setAnnouncement(Announcement);
        }
    }

    public void setServerIP(String serverIP) {
        ClientController.serverIP = serverIP;
    }

    public Vector<Message> getOfflineMessages() {
        try {
            return getService().getOfflineMessage(clientServiceImpl);
        } catch (RemoteException ex) {
            Logger.getLogger(ClientController.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    public void updateMembersList(Account account, ChatRoomInt room) throws RemoteException, AssertionError {
        ChatWindow window = getChatRooms().get(room);
        Vector<Account> accounts = room.getChatRoomMembers();
        System.out.println("At client roomMembers after removing=" + accounts.size());
        DefaultListModel model;
        if (window != null) {
            model = (DefaultListModel) window.getMember_list().getModel();
            model.removeElement(account);
            window.getMember_list().setModel(model);
            window.setChatRoom(room);
        } else {
            System.out.println("------------Window is NULL----------");
        }

    }
    public void addToMemberList(Account account,ChatRoomInt room)throws RemoteException{
        DefaultListModel model;  
        ChatWindow window = getChatRooms().get(room);
        model=(DefaultListModel)window.getMember_list().getModel();  
        model.addElement(account);
        window.getMember_list().setModel(model);
        window.setChatRoom(room);
    }
}
